#!/usr/bin/python3

import os
import json
import re
import subprocess
import shutil
import time
import random

import utils

# 导入 当前目录
import sys
from typing import Any


sys.path.insert(0, os.path.split((os.sys.argv[0]))[0])

# from bilibili_info  import main as bili_main
from douban_info import main as douban_main


# 注意 所有 路径 都是相对文件服务器的  根 url  http://sever.lan:9966/

# # 文件夹 后缀 这些都是 第二层目录(组为第一层, 即组内目录!!)
##  ..isvod  # 多个 (电影|电视)  多个VOD组成一个VOD
##  ..isfolder # 是目录
##  ..need_title  # 不忽略 内部视频 标题(忽略=只有序号!)并使用filters
##  ..need_title2  # 不忽略标题&&使用filters2
## .others
##  x.others/y.bili.others  # b站视频 只能出现在 *.others/下 比如 aa.others/bb..bili.others

############## 前缀 就是为了排序用的.  将相关的vod排在一起!!!
##  aaaa..ispretitle/y/ # aaaa-name
##  aaaa..ispretitle/{y1,y2,...} # 其中y1,y2,..都是一个vod



class Logger():
    def __init__(self,path) -> None:
        self.fd=open(path,"w")

    def __call__(self, *args: Any, **kwds: Any) -> Any:
        print(*args)
        print(*args,file=self.fd)
        # fd.write("{}\n".format(s))
        # fd.flush()

    def close(self):
        self.fd.close()


def load_jsonfile(path,fallback=None):
    try:
        with open(path,"r") as f:
            info=json.load(f)
            if info:
                return info
    except Exception as e:
        log("       [e] open or parse json file error : {}".format(path))
    info=None
    if fallback:
        info=fallback()
    return info

def save_jsonfile(obj,path):
    try:
        jsonstr=json.dumps(obj)
    except Exception as e:
        log("[E] dumps json error : "+path)
        log(e)

    try:
        with open(path,"w") as f:
            n=f.write(jsonstr)
            log("[i] json data saved len ={}".format(n))
    except Exception as e:
        log("[E] save json error : "+path)
        log(e)



def _suffix(name,suffix):
    res=False
    if name.endswith(suffix):
        name=name.removesuffix(suffix)
        res=True
    return res,name

# def is_multi_vod(name):
#     return _suffix(name,"..isvod")



def process_subfolder_others(store,parent,filename,name):
    def _process_bili(store,parent,filename):
        # return
        # TODO
        cur=os.path.abspath((os.curdir))
        os.chdir(os.path.join(parent,filename))
        # bili_main(path=os.path.join(parent,filename))
        os.chdir(cur)

    def process(suf,inner_process=None):
        # .bili.others
        suffix=".{}.others".format(suf)
        if filename.endswith(suffix):
            # # p=os.path.join(parent,filename)
            # # vod_name=filename.removesuffix(suffix)
            # # pic=FILE__custom_pic
            # if inner_process: # 不在这里处理. 单独处理
            #     inner_process(store,parent,filename)
            return True
        return False

    if process("bili",_process_bili,"bili"):
        return True
    if process("xigua"):
        return True
    return False


filters=(
    r"[_\.\-\[\]/]",
    r"[,;]",
    r"[【】《》（）]",
    r"[hx]26[45]",
    r"mkv",
    r"mp4",
    r"aac",
    r"hevc",
    r"avc",
    r"蓝光",
    r"blueray",
    r"高清",
    r"\\",
    r"  +"
)

filters2=(
    r"[_\.\-\[\]/]",
    r"[,;]",
    r"[【】《》（）]",
    r"\\",
    r"  +"
)

def make_vod_play_url(videos,vod_dir,need_title=0):
    # 相对路径, 相对于vod目录
    ## vod目录 xxxx
    ##    title$01.mp4#title2$yyy/02.mp4#....

    ## need_title : 0 序号即可 ; 1 : 使用序号+视频文件(夹)名.  2 : 同1但不做filter
    ### xxxx/yyy.mp4  -> yyy 作为名字
    ### xxxx/aaa/bbb.mp4 -> aaa作为名字
    res=[]
    count=1
    length=len(videos)
    for i,v in enumerate(videos):
        parent=v["parent"]
        video=v["video"]

        isSeasonSpliter,title=__multi_season_in_one_vod(parent,video)
        if isSeasonSpliter:
            # 多部合一  , 提示视频  0000000000x0N.mp4
            count=1
            res.append("{}${}".format(title,os.path.join(parent,video)))
            continue

        title=""
        if need_title>0:
            tmp=parent.removeprefix(vod_dir).strip("/ ")
            if tmp:
                title=tmp+" "+video
            else:
                title=video
            # title.split(".")[:-1]
            kw=title
            if need_title==1:
                _filters=filters
            elif need_title==2:
                _filters=filters2
            for filter in _filters:
                kw=re.sub(filter," ",kw,flags=re.I)

            # kw=re.sub("[_\.\-]"," ",kw)
            kw=list(set(kw.split(" ")[:-1]))
            kw.sort()
            kw2=[]
            for i,k1 in enumerate(kw):
                for k2 in kw[i+1:]:
                    if k1 in k2:
                        continue
                kw2.append(k1)

            title=" ".join(kw2)
            title=title.strip(" /.-_")

        if length>9999:
            strCount="%05d "%count
        elif length>999:
            strCount="%04d "%count
        elif length>99:
            strCount="%03d "%count
        elif length>9:
            strCount="%02d "%count
        else:
            strCount="%d "%count
        if not title.startswith(strCount):
            title="%s%s"%(strCount,title)
        count+=1
        title=title.strip(" /\n-_,;.!@$%^&*(){}[]?<>")
        res.append("{}${}".format(title,os.path.join(parent,video)))

    return "#".join(res)

def gen_pic_by_ffmpeg(src_video,dst):
    getDuaraton=["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", src_video]

    try:
        # os.system 是异步的....
        ## 换 subprocess
        res=subprocess.run(getDuaraton, stdout=subprocess.PIPE)
        duaraton=res.stdout.decode('utf8').strip("\n")
        log("  [I] duration=",duaraton)
        d1=int(float(duaraton)/2)
        d2=int(float(duaraton)/3)

        ffmpeg_cmd=["ffmpeg",'-v','error', "-ss", "%d"%d1, "-i", src_video, "-frames:v", "1", "-vf", "crop=in_h*0.66:in_h:in_w/2-in_h*0.33:0", dst]
        subprocess.run(ffmpeg_cmd,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
        # # 不搞备选了!!!
        # ffmpeg_cmd=["ffmpeg",'-v','error', "-ss", "%d"%d2, "-i", src_video, "-frames:v", "1", "-vf", "crop=in_h*0.66:in_h:in_w/2-in_h*0.33:0", dst+".2.jpg"]
        # subprocess.run(ffmpeg_cmd,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)

        if subprocess.returncode==0:
            log("[I] ffmpeg extract .jpg OK")
            log("[I] ffmpeg extract .jpg OK")
            log("[I] ffmpeg extract .jpg OK")
        else:
            log("[E] ffmpeg extract .jpg failed")
            log("    May be ffmpeg not installed")

    except:
        log("[E] exception :: ffmpeg extract .jpg")



t_last_douban=0
err_count_douban=0
def process_vod(store,parent,filename,name,no_douban=True):
    global t_last_douban
    global err_count_douban


    # filename : vod_dir
    p=os.path.join(parent,filename)
    log("[info] process : {}".format(p))
    

    pic=FILE__pic
    douban_file=FILE__douban_file

    if no_douban:
        pic=FILE__custom_pic
        info={

        }
        ffmpeg_pic=os.path.join(parent,filename,pic)

        vs=getVideos(p)
        if not get_file_size(ffmpeg_pic)>1 and len(vs)>0:
            # ffmpeg
            gen_pic_by_ffmpeg(os.path.join(vs[0]["parent"],vs[0]["video"]),ffmpeg_pic)
    else:
        douban_json_file=os.path.join(p,douban_file)
        info=load_jsonfile(douban_json_file)
        if not info:
            nameX=name

            t_now=time.time()
            delta=8+random.random()*8-round(t_now-t_last_douban)
            t_last_douban=t_now
            if delta>0:
                time.sleep(delta)
            for i in range(2):
                data=douban_main(nameX,p)
                if data:
                    info=data
                    save_jsonfile(info,douban_json_file)
                    # time.sleep(3)
                    break
                else:
                    for j in range(3):
                        log("[E] no douban info found and try download failed : {}".format(p))
                        time.sleep(3)
                    if i==0:
                        waitSec=60*(1+err_count_douban)
                        log("       -> wait {} sec , adn  try again ".format(waitSec))
                        time.sleep(waitSec)
            if not data:
                err_count_douban+=1
                return False
            err_count_douban=0


def get_file_size(file_path):
    if not os.path.exists(file_path):
        return 0
    file_info = os.stat(file_path)
    return file_info.st_size

def isVideo(path):
    _,ext=os.path.splitext(path)
    if ext == "":
        return False

    if ext in video_suffix:
        return True
    return False

def getVideos(dir):
    # cur=os.path.abspath((os.curdir))
    # os.chdir(dir)
    # 不搞层层 相对了..
    # 直接相对于 根 url
    vs=[]
    for p,d,f in os.walk(dir):
        for ff in f:
            if ff.startswith("0000000000"):
                continue
            if isVideo(ff):
                vs.append({
                    "parent":p.removeprefix("./"),
                    "video":ff
                })
    vs.sort(key=lambda v:os.path.join(v["parent"],v["video"]))
    # os.chdir(cur)
    return vs






## group_main
def group_main(store,parent,no_douban=True,loopDepth=0):
    if loopDepth>10:
        return
    
    no_douban=no_douban or folder.endswith(".others")
    loopDepth+=1
    folders=utils.getDirs(parent)
    for folder in folders:
        if folder.endswith(".off"):
            continue
        if folder.startswith("sub_"):
            # 可以 套多层目录
            if process_subfolder_others(store,parent,folder):
                continue
            group_main(store,os.path.join(parent,folder),no_douban,loopDepth)
            continue

        # 这层 = 排序用的  
        # # group/sorter/film
        # # group/sub_sorter_xxxx/sorter/film/
        dir=os.path.join(parent,folder)
        films=utils.getDirs(dir)
        log("[Debug] vod dir : "+dir)
        log("[Debug] films : ",films)
        
        for film in films: # dir
            if film.endswith(".off"):
                continue
            log("[Debug] vod dir : "+film)
            name=film
            process_vod(store,dir,film,name,no_douban)


## main
def main():
    if len(os.sys.argv)<2:
        log("[E] need arg1 : ")
        log("        python3 {} xxxx/videos/".format(os.sys.argv[0]))
        exit(1)

    rootdir=os.sys.argv[1]
    if not os.path.exists(rootdir):
        log("[E] dir not exists : {}".format(rootdir))
        exit(2)
    rootdir=rootdir.rstrip("/")

    # video_dir="videos"
    rootdir,video_dir=os.path.split(rootdir)

    cur=os.path.abspath((os.curdir))
    if rootdir!="":
        os.chdir(rootdir)

    filter_pre=[]
    filter_suf=[".off"]
    groups=utils.getDirs(rootdir=video_dir,filter_pre=filter_pre,filter_suf=filter_suf)

    log("[INFO] start")
    log("[Debug] ", groups)
        
    store=[]

    for g in groups:
        if not g.startswith("group_"):
            continue

        log("[Debug] "+g)
        group_name_txt=os.path.join(video_dir,g,FILE__group_name)
        if not os.path.exists(group_name_txt):
            continue
        no_douban=g.endswith(".others")
        group_main(store,os.path.join(video_dir,g),no_douban)

    os.chdir(cur)




def post_main():
    for k in doubanid_STORE.keys():
        log(k,doubanid_STORE[k])
    log("__________")
    for k in doubanid_STORE.keys():
        l=len(doubanid_STORE[k])
        if(l>1):
            log("")
            log("{} count={}".format(k,l),k,doubanid_STORE[k])
    # close fd
    log.close()



###############################################
###############################################
###############################################

video_suffix=[
    ".dff",".dsf",".mp3",".aac",".wav",".wma",".cda",".flac",".m4a",".mid",".mka",
    ".mp2",".mpa",".mpc",".ape",".ofr",".ogg",".ra",".wv",".tta",".ac3",".dts",
    ".tak",".webm",".wmv",".mpeg",".mov",".ram",".swf",".mp4",".avi",".rm",".rmvb",
    ".flv",".mpg",".mkv",".m3u8",".ts",".3gp",".asf"
]
###

# VOD_STORE={}
doubanid_STORE={}

FILE__pic="__poster.jpg"
# FILE__custom_pic="__custom_poster.jpg"
FILE__custom_pic=FILE__pic
FILE__douban_file="__douban_info.json"
FILE__group_name="group_name.txt"

log_path="/tmp/__log__gen_video_list.log"
log=Logger(log_path)


main()
post_main()

print("log_path=",log_path)

##################################
##################################
##################################


